package com.sentrix.auto.printercenter.presentation.center;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.text.StrFormatter;
import com.sentrix.auto.printercenter.common.*;
import com.sentrix.auto.printercenter.infrastructure.agentserver.AgentClientManager;
import com.sentrix.auto.printercenter.application.PrinterService;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sentrix.auto.printercenter.infrastructure.agentserver.WebSocketResSyncHandler;
import com.sentrix.auto.printercenter.infrastructure.agentserver.dto.BaseWebSocketResMsg;
import com.sentrix.auto.printercenter.infrastructure.agentserver.dto.CallMethodType;
import com.sentrix.auto.printercenter.infrastructure.agentserver.dto.BaseQZPrintReq;
import com.sentrix.auto.printercenter.presentation.center.dto.PrintSimpleReqDto;
import com.sentrix.auto.printercenter.presentation.center.dto.PrinterResDto;
import com.sentrix.auto.printercenter.presentation.common.BaseResponse;
import com.sentrix.auto.printercenter.presentation.common.DataResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.NotNull;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.List;

@Slf4j
@RestController
@RequestMapping("printer")
@Tag(name = "打印机管理", description = "打印机管理")
public class PrinterController {

    private final ObjectMapper objectMapper = new ObjectMapper();
    private final WebSocketResSyncHandler syncHandler = WebSocketResSyncHandler.instance();
    private final AgentClientManager printClientManager = AgentClientManager.instance();

    @Autowired
    private PrinterService printService;

    /**
     * 根据agentCode查询agent下qztray的版本
     *
     * @param mac
     * @return
     * @throws IOException
     */
    @Operation(summary = "查询agent下qztray的版本", description = "根据agentCode查询agent下qztray的版本")
    @Parameter(name = "agentCode", required = true, description = "agentCode")
    @GetMapping("{agentCode}/qztray")
    public BaseResponse info(@PathVariable("agentCode") String mac) throws IOException {
        log.info("接受到查询请求:{}", mac);
        if (printClientManager.isClientOnline(mac)) {
            BaseQZPrintReq qzPrintReqParam = new BaseQZPrintReq(IdGenerator.generateId());
            qzPrintReqParam.setCall(CallMethodType.GET_VERSION);
            log.info("消息uid:{}", qzPrintReqParam.getUid());
            BaseWebSocketResMsg webSocketResMsg = printClientManager.sendMessage(mac, qzPrintReqParam, 5);
            return new BaseResponse(webSocketResMsg.getUid(), webSocketResMsg.isSuccess(), 100, webSocketResMsg.getResult());
        } else {
            return new BaseResponse(mac, false, 200, "can not find agent by agentCode or offline!");
        }
    }

    /**
     * 根据agentCode查询agent下的所有打印机
     *
     * @param agentCode
     * @return
     * @throws IOException
     */
    @Operation(summary = "根据agentCode查询agent下的所有打印机", description = "根据agentCode查询agent下的所有打印机")
    @Parameter(name = "agentCode", required = true, description = "agentCode")
    @GetMapping("list")
    public DataResponse printer(@RequestParam("agentCode") String agentCode) throws IOException {
        List<PrinterResDto> printers = printService.findPrinterByAgent(agentCode, PrinterResDto::fromDomain);
        return new DataResponse(printers);
    }

    /**
     * 启用/禁用打印机
     *
     * @param printerCode
     * @param enable
     * @return
     * @throws IOException
     */
    @Operation(summary = "启用/禁用打印机", description = "启用/禁用打印机")
    @Parameters({
            @Parameter(name = "printerCode", required = true, description = "打印机编码"),
            @Parameter(name = "enable", required = true, description = "是否启用")
    })
    @GetMapping("{printerCode}/enable")
    public BaseResponse enablePrinter(@PathVariable("printerCode") String printerCode, @RequestParam("enable") @NotNull(message = "enable can not be null") Boolean enable) throws IOException {
        printService.enablePrinter(printerCode, enable);
        return new BaseResponse("1", true, 200, "success");
    }

    /**
     * 打印打印机code的二维码
     *
     * @param desPrinterCode 目标打印机编码
     * @return
     */
    @Operation(summary = "打印打印机code的二维码", description = "打印打印机code的二维码")
    @Parameters({
            @Parameter(name = "printerCode", required = true, description = "打印机编码"),
            @Parameter(name = "desPrinterCode", required = true, description = "目标打印机编码")
    })
    @GetMapping("{printerCode}/print/qr")
    public BaseResponse printPrinterCode(@PathVariable("printerCode") String printerCode, @RequestParam("desPrinterCode") String desPrinterCode) {
        PrinterResDto printer = printService.find(printerCode);
        AssertUtil.assertNotNull(printer, "no printer for printerCode:" + printerCode);
        PrinterResDto desPrinter = printService.find(desPrinterCode);
        AssertUtil.assertNotNull(desPrinter, "no printer for desPrinterCode:" + desPrinterCode);
        PrintSimpleReqDto simpleReqDto = PrintSimpleReqDto.builder()
                .printerCode(printer.getCode())
                .orderCode(UUID.fastUUID().toString())
                .data(QRCodeUtil.generateQRCodeBase64(desPrinter.getCode(), 300, 300, desPrinter.getName(), desPrinter.getCode()))
                .dataType(PrintConst.DataType.IMAGE.name())
                .dataFormat("png")
                .dataEncodeFormat(PrintConst.DataEncodeFromat.BASE64.name())
                .build();
        printService.print(simpleReqDto);
        return new BaseResponse("1", true, 200, "success");
    }

    /**
     * 根据agentCode【实时】查询agent下的所有打印机状态
     *
     * @param mac         mac地址
     * @param printerName 打印机名称
     * @return
     * @throws IOException
     */
    @Operation(summary = "根据agentCode【实时】查询agent下的所有打印机状态", description = "根据agentCode查询agent下的所有打印机状态，直接向agent发送websocket请求")
    @GetMapping("{agentCode}/{printerName}/state")
    public BaseResponse printerState(@PathVariable("agentCode") String mac, @PathVariable("printerName") String printerName) throws IOException {
        if (printClientManager.isClientOnline(mac)) {
            //1、先启动监听
            BaseQZPrintReq<ListeningPrinterParam> listeningReq = new BaseQZPrintReq<>(IdGenerator.generateId());
            listeningReq.setParams(ListeningPrinterParam.builder().printerNames(new String[]{}).build());
            listeningReq.setCall(CallMethodType.PRINTERS_START_LISTENING);
            printClientManager.sendMessage(mac, listeningReq, 30);
            BaseWebSocketResMsg webSocketResMsg = syncHandler.waitForResponse(listeningReq.getUid(), 5);
            log.info("监听结果：{}", webSocketResMsg);
            //2、获取状态
            BaseQZPrintReq<?> qzPrintReqParam = new BaseQZPrintReq<>(IdGenerator.generateId());
            qzPrintReqParam.setCall(CallMethodType.PRINTERS_GET_STATUS);
            printClientManager.sendMessage(mac, qzPrintReqParam, 30);
            webSocketResMsg = syncHandler.waitForResponse(qzPrintReqParam.getUid(), 5);
            return new BaseResponse(webSocketResMsg.getUid(), webSocketResMsg.isSuccess(), 100, webSocketResMsg.getResult());
        } else {
            return new BaseResponse(mac, false, 200, StrFormatter.format("{}:agent is offline!", mac));
        }
    }


    /**
     * A4纸扫码打印
     *
     * @param printerCode
     * @return
     * @throws IOException
     */
    @Operation(summary = "A4纸扫码打印", description = "A4纸扫码打印")
    @GetMapping("{printerCode}/print/file-simple")
    public DataResponse print(@PathVariable("printerCode") String printerCode) throws IOException {
        return new DataResponse("1", true, 200, "打印成功");
    }


    /**
     * 删除打印机
     *
     * @param printerCode
     * @return
     */
    @Operation(summary = "删除打印机", description = "删除打印机")
    @Parameter(name = "printerCode", required = true, description = "打印机编码")
    @GetMapping("{printerCode}/remove")
    public BaseResponse remove(@PathVariable("printerCode") String printerCode) {
        printService.remove(printerCode);
        return new BaseResponse("1", true, 200, "删除成功");
    }
}
